package cn.dyn.funchat.utils;


import cn.hutool.core.util.RandomUtil;

import java.security.SecureRandom;
import java.util.Random;

/**
 * NanoId，一个小型、安全、对 URL友好的唯一字符串 ID 生成器，特点：
 *
 * <ul>
 *     <li>安全：它使用加密、强大的随机 API，并保证符号的正确分配</li>
 *     <li>体积小：只有 258 bytes 大小（压缩后）、无依赖</li>
 *     <li>紧凑：它使用比 UUID (A-Za-z0-9_~)更多的符号</li>
 * </ul>
 *
 * <p>
 * 此实现的逻辑基于JavaScript的NanoId实现，见：https://github.com/ai/nanoid
 *
 * @author David Klebanoff
 */
public class NanoIdUtil {

    /**
     * 默认随机数生成器，使用{@link SecureRandom}确保健壮性
     */
    private static final SecureRandom DEFAULT_NUMBER_GENERATOR = RandomUtil.getSecureRandom();

    /**
     * 默认随机字母表，使用URL安全的Base64字符
     */
    private static final char[] DEFAULT_ALPHABET =
            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    /**
     * 默认长度
     */
    public static final int DEFAULT_SIZE = 21;

    /**
     * 生成伪随机的NanoId字符串，长度为默认的{@link #DEFAULT_SIZE}，使用密码安全的伪随机生成器
     *
     * @return 伪随机的NanoId字符串
     */
    public static String randomNanoId() {
        return randomNanoId(DEFAULT_SIZE);
    }

    /**
     * 生成伪随机的NanoId字符串
     *
     * @param size ID长度
     * @return 伪随机的NanoId字符串
     */
    public static String randomNanoId(int size) {
        return randomNanoId(null, null, size);
    }

    /**
     * 生成伪随机的NanoId字符串
     *
     * @param random   随机数生成器
     * @param alphabet 随机字母表
     * @param size     ID长度
     * @return 伪随机的NanoId字符串
     */
    public static String randomNanoId(Random random, char[] alphabet, int size) {
        if (random == null) {
            random = DEFAULT_NUMBER_GENERATOR;
        }

        if (alphabet == null) {
            alphabet = DEFAULT_ALPHABET;
        }

        if (alphabet.length == 0 || alphabet.length >= 256) {
            throw new IllegalArgumentException("Alphabet must contain between 1 and 255 symbols.");
        }

        if (size <= 0) {
            throw new IllegalArgumentException("Size must be greater than zero.");
        }

        final int mask = (2 << (int) Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1;
        final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);

        final StringBuilder idBuilder = new StringBuilder();

        while (true) {
            final byte[] bytes = new byte[step];
            random.nextBytes(bytes);
            for (int i = 0; i < step; i++) {
                final int alphabetIndex = bytes[i] & mask;
                if (alphabetIndex < alphabet.length) {
                    idBuilder.append(alphabet[alphabetIndex]);
                    if (idBuilder.length() == size) {
                        return idBuilder.toString();
                    }
                }
            }
        }
    }

    /*



lsmR3xSO9FDFjbsTx7N5
ZHH8eRJGaP6QzGZFMZ9E
T4v66owLrINnBH2glYru
Talu402ZXPK2QRLuOJ7D
ShHj7Zum8PHhW1QhVfIn
UvI3mhxSHuqMjTgbuIAR
XpQH3I6f9isc0NNUPves
mdnRBpegaGjOxC4p4nKL
OL5EQKGvsGzkN9ZOrdNg
2ktIGfwKnEpY3QPJiczf
ERFkrzpdbizq3m72nbYV
HQ5kuMjTe94NUSZdmfsG
7ubp3b2vjCR8CAirq7dy
bIZVH2EcXpeb7o7JaLp6
QEI7FDhC87ui9a7jfEwO
hhFBiqL4M68dswC8yrPL
3rIR1PWqBqAddYgZSpcn
licVqutyRLGjOIVI0mIL
UNcNdhm3chrogFkxNaAr
oQWRKPHA7Fq5lhATWgI3
nRNwgKZd5HSufSv5FaCF
GKghQwxjdQMmXZwEH3sR
QNCo6oNswaDWVbK75VAM
4Ni0EMHK3Gp6ZY71u0Ak
dxsVZwSCE1PTI3LvSD8h
PpSrGz1FA5ipapQZnT2x
1kxfnh5o8koB5zKl5xqj
uTvWSznnqCOm3CHlZayv
yU1a0LDSlVe14pgjiOCJ
qfvPX7q4nHaSNx5G69eP
DRr7VdolQWcLj5x7KqY3
oavhPXJ0GY64uzbMs2x6
JDvhhmLfB98l2pNraoe7
YvvNA7TcKYZV01401GSQ
NYnhYpHDgwiuXPrvVVK1
nsQ0NZt2GAeA52TLELOD
OvNEsVNAPubHAP5yOnlP
HtLTMrBWkN2vs7lpxXiR
m2z7wKo0V56T9KrtaupK
6wIuXYee7PTy4udB11bP
I6x3pgNTNOL981MH6B18
UnfoXWvEXwNwWlAKEAVC
JwH6lSQMM6nSKSQeh1GD
RmHAbmVoJ5KNe49ZcGvG
V2WZJTvZE6RkdJNP2FHx
     */
    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            System.out.println(randomNanoId(20));
        }
    }
}